package nio.nio.group;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * @author 帅小伙
 * @date 2022/1/15
 * @description
 */
public class GroupChatServer {


    private Selector selector;
    private ServerSocketChannel listenChannel;
    private static final int PORT = 6667;

    /*
    * 设置成是否阻塞
    * 绑定端口
    * 注册到selector   并设置状态
    * */
    public GroupChatServer() {
        try {
            selector = Selector.open();
            listenChannel = ServerSocketChannel.open();
            listenChannel.configureBlocking(false);
            listenChannel.bind(new InetSocketAddress(PORT));
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //循环监听
    public void listen() {

        System.out.println("监听线程:"+Thread.currentThread().getName());
        try {

            while (true) {
                // 注册到selector的监听线程
                int count = selector.select();
                if (count > 0) {
                    // 获取注册keys
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();

                        // 判断监听到的类型
                        if (key.isAcceptable()) {
                            SocketChannel sc = listenChannel.accept();
                            sc.configureBlocking(false);
                            // 注册到selector
                            sc.register(selector, SelectionKey.OP_READ);
                            // 提示
                            System.out.println(sc.getRemoteAddress() + " 上线了");
                        }

                        // 读事件   通道可读
                        if (key.isReadable()) {
                            // 处理读
                            readData(key);
                        }

                    }
                    // key 删除  防止重复处理
                   iterator.remove();
                } else {
                    System.out.println("等待.....");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void readData(SelectionKey key) {
        //定义一个socketChannel
        SocketChannel channel = null;

        try {
            channel = (SocketChannel) key.channel();
            // 创建缓存buffer 读数据
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int count = channel.read(buffer);
            if (count > 0) {
                String msg = new String(buffer.array(),0,count);
                // 输出
                System.out.println("from 客户端" + msg);

                // 向其他客户端转发消息   写一个方法
                sendInfoToOtherClient(msg,channel);
            }
        } catch (IOException e) {
            try {
                System.out.println(channel.getRemoteAddress()+" 离线了");
                // 取消注册  关闭通道
                key.cancel();
                channel.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }


    // 转发消息给其他通道
    private void sendInfoToOtherClient(String msg, SocketChannel self) throws IOException {
        System.out.println("转发线程:"+Thread.currentThread().getName());
        System.out.println("服务器转发消息");

        // 遍历所有注册到selector的key
        for (SelectionKey key : selector.keys()) {
            Channel targetChannel = key.channel();
            // 排除自己和服务器
            if (targetChannel instanceof SocketChannel && targetChannel != self) {
                SocketChannel dest = (SocketChannel) targetChannel;
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                dest.write(buffer);
            }
        }
    }


    public static void main(String[] args) {
        GroupChatServer groupChatServer = new GroupChatServer();

        groupChatServer.listen();
    }

}
